package pojo;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

import entity.worker;
import utils.WorkCalendar;

public class WorkerHandle {
    private String Id;                      // 序号
    private String employeeName;            // 姓名
    private String employeeNo;              // 人员编码
    private String mdsWorkerGroupName;      // 所属制造单元
    private Double capacityCodfficient;     // 能力系数
    private Double efficiencyCodfficient;   // 劳动效率
    private List<TaskAssignment> assignments = new ArrayList<>(); // 分配的任务
    private double available;               // 可用时间
    private double accumulatedWorkHours;    // 累计工作时间
    private WorkCalendar workCalendar=new WorkCalendar();      // 工作日历对象

    // 定义每天工作小时数
    private static final double DAILY_WORK_HOURS = 8.0;

    public WorkerHandle() {
    }

    public WorkerHandle(worker w) {
        this.Id = w.getId();
        this.employeeName = w.getEmployeeName();
        this.employeeNo = w.getEmployeeNo();
        this.mdsWorkerGroupName = w.getMdsWorkerGroupName();
        this.capacityCodfficient = w.getCapacityCodfficient();
        this.efficiencyCodfficient = w.getEfficiencyCodfficient();
    }

    /**
     * 判断工人能否加工对应的零件
     */
    public boolean canHandle(TaskAssignment taskAssignment) {
        double handle = taskAssignment.getItemDifficulty();
        return capacityCodfficient >= handle;
    }

    /**
     * 分配任务到工人任务列表
     */
    public void assignTask(TaskAssignment taskAssignment) {
        assignments.add(taskAssignment);
    }

    /**
     * 移除最后分配的任务
     * 注意：学习曲线只考虑当前任务的数量
     */
    public void removeLastTaskAssignment() {
        if (!assignments.isEmpty()) {
            TaskAssignment last = assignments.remove(assignments.size() - 1);

            // 恢复可用时间，考虑学习曲线效应
            double totalTime = calculateTaskTotalTime(last);
            this.available += totalTime;
            this.accumulatedWorkHours -= totalTime;
        }
    }

    /**
     * 计算任务总时间（包括学习曲线效应）
     * 学习曲线只考虑当前任务的数量
     */
    public double calculateTaskTotalTime(TaskAssignment task) {
        double baseTime = task.getMakeCycle();
        double totalTime = task.getPreCycle();

        // 计算总时间，考虑学习曲线效应
        double alpha = -0.4815;
        double m = 0.3185;

        for (int i = 1; i <= task.getAssignedQuantity(); i++) {
            double learningTerm = m + (1 - m) * Math.pow(i, alpha);
            totalTime += learningTerm * baseTime;
        }

        return totalTime;
    }

    /**
     * 获取任务的开始时间
     */
    public LocalDateTime getLatestTaskStartTime() {
        if (assignments.isEmpty()) return null;
        return assignments.get(assignments.size() - 1).getStartTime();
    }

    /**
     * 获取任务的截止时间
     */
    public LocalDateTime getLatestTaskEndTime() {
        if (assignments.isEmpty()) return null;
        return assignments.get(assignments.size() - 1).getEndTime();
    }

    /**
     * 结合工作日历调整工人的工作时间
     */
    public void recalculateSchedule(LocalDate baseDate) {
        // 按截止日期排序任务
        Collections.sort(assignments, Comparator.comparing(TaskAssignment::getDeadline));
        this.accumulatedWorkHours = 0.0;

        // 从基准日期开始
        LocalDateTime currentTime = LocalDateTime.of(baseDate, LocalTime.of(0, 0));

        // 记录每个任务的实际开始和结束时间
        Map<TaskAssignment, LocalDateTime[]> taskTimings = new LinkedHashMap<>();

        // 第一遍：计算每个任务需要的时间
        for (TaskAssignment taskAssignment : assignments) {
            double needHours = calculateTaskTotalTime(taskAssignment);
            LocalDateTime taskStart = null;
            LocalDateTime taskEnd = null;
            double remainingHours = needHours;

            while (remainingHours > 0) {
                // 确保当前时间在工作日，否则跳到下一个工作日
                if (workCalendar.isWorkDay(currentTime.toLocalDate()) != 1) {
                    currentTime = jumpToNextWorkingDay(currentTime);
                    continue;
                }

                // 如果当前是新的一天，设置为当天开始
                if (currentTime.toLocalTime().equals(LocalTime.of(0, 0))) {
                    currentTime = LocalDateTime.of(currentTime.toLocalDate(), LocalTime.of(0, 0));
                }

                double toSchedule = Math.min(remainingHours, DAILY_WORK_HOURS);
                if (taskStart == null) {
                    taskStart = currentTime;
                }

                // 计算当前工作块的结束时间
                taskEnd = currentTime.plusSeconds((long) (toSchedule * 3600));
                remainingHours -= toSchedule;
                currentTime = taskEnd;
                this.accumulatedWorkHours += toSchedule;

                // 如果还有剩余工作，跳到下一个工作日
                if (remainingHours > 0) {
                    currentTime = jumpToNextWorkingDay(currentTime);
                }
            }

            taskTimings.put(taskAssignment, new LocalDateTime[]{taskStart, taskEnd});
        }

        // 第二遍：设置任务的开始和结束时间，确保没有重叠
        for (Map.Entry<TaskAssignment, LocalDateTime[]> entry : taskTimings.entrySet()) {
            TaskAssignment task = entry.getKey();
            LocalDateTime[] times = entry.getValue();
            task.setStartTime(times[0]);
            task.setEndTime(times[1]);
        }
    }

    /**
     * 跳转到下一个工作日
     */
    private LocalDateTime jumpToNextWorkingDay(LocalDateTime currentTime) {
        LocalDate nextDay = currentTime.toLocalDate().plusDays(1);

        // 找到下一个工作日
        while (workCalendar.isWorkDay(nextDay) != 1) {
            nextDay = nextDay.plusDays(1);
        }

        return LocalDateTime.of(nextDay, LocalTime.of(0, 0));
    }

    // Getters and setters
    public String getId() {
        return Id;
    }

    public void setId(String id) {
        Id = id;
    }

    public String getEmployeeName() {
        return employeeName;
    }

    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }

    public String getEmployeeNo() {
        return employeeNo;
    }

    public void setEmployeeNo(String employeeNo) {
        this.employeeNo = employeeNo;
    }

    public String getMdsWorkerGroupName() {
        return mdsWorkerGroupName;
    }

    public void setMdsWorkerGroupName(String mdsWorkerGroupName) {
        this.mdsWorkerGroupName = mdsWorkerGroupName;
    }

    public Double getCapacityCodfficient() {
        return capacityCodfficient;
    }

    public void setCapacityCodfficient(Double capacityCodfficient) {
        this.capacityCodfficient = capacityCodfficient;
    }

    public Double getEfficiencyCodfficient() {
        return efficiencyCodfficient;
    }

    public void setEfficiencyCodfficient(Double efficiencyCodfficient) {
        this.efficiencyCodfficient = efficiencyCodfficient;
    }

    public List<TaskAssignment> getAssignments() {
        return assignments;
    }

    public void setAssignments(List<TaskAssignment> assignments) {
        this.assignments = assignments;
    }

    public double getAvailable() {
        return available;
    }

    public void setAvailable(double available) {
        this.available = available;
    }

    public double getAccumulatedWorkHours() {
        return accumulatedWorkHours;
    }

    public void setAccumulatedWorkHours(double accumulatedWorkHours) {
        this.accumulatedWorkHours = accumulatedWorkHours;
    }

    public WorkCalendar getWorkCalendar() {
        return workCalendar;
    }

    public void setWorkCalendar(WorkCalendar workCalendar) {
        this.workCalendar = workCalendar;
    }

    // 在WorkerHandle类中添加
    public void removeLastTaskAssignment(Map<String, Integer> assignedQuantityCache) {
        if (!assignments.isEmpty()) {
            TaskAssignment last = assignments.remove(assignments.size() - 1);

            // 恢复可用时间，考虑学习曲线效应
            double totalTime = calculateTaskTotalTime(last);
            this.available += totalTime;
            this.accumulatedWorkHours -= totalTime;

            // 更新缓存
            String taskKey = last.getItemID() + "_" + last.getOrderCode();
            if (assignedQuantityCache.containsKey(taskKey)) {
                int currentQuantity = assignedQuantityCache.get(taskKey);
                int newQuantity = Math.max(0, currentQuantity - last.getAssignedQuantity());
                if (newQuantity == 0) {
                    assignedQuantityCache.remove(taskKey);
                } else {
                    assignedQuantityCache.put(taskKey, newQuantity);
                }
            }
        }
    }

    // 在WorkerHandle类中添加
    public void incrementalScheduleUpdate(TaskAssignment newTask, LocalDate baseDate) {
        // 如果任务列表为空，直接调用完整的重新计算
        if (assignments.isEmpty() || assignments.size() == 1) {
            recalculateSchedule(baseDate);
            return;
        }

        // 获取最后一个任务的结束时间作为新任务的开始时间
        LocalDateTime currentTime = getLatestTaskEndTime();
        if (currentTime == null) {
            currentTime = LocalDateTime.of(baseDate, LocalTime.of(0, 0));
        }

        // 计算新任务需要的时间
        double needHours = calculateTaskTotalTime(newTask);
        LocalDateTime taskStart = null;
        LocalDateTime taskEnd = null;
        double remainingHours = needHours;

        while (remainingHours > 0) {
            // 确保当前时间在工作日，否则跳到下一个工作日
            if (workCalendar.isWorkDay(currentTime.toLocalDate()) != 1) {
                currentTime = jumpToNextWorkingDay(currentTime);
                continue;
            }

            // 如果当前是新的一天，设置为当天开始
            if (currentTime.toLocalTime().equals(LocalTime.of(0, 0))) {
                currentTime = LocalDateTime.of(currentTime.toLocalDate(), LocalTime.of(0, 0));
            }

            double toSchedule = Math.min(remainingHours, DAILY_WORK_HOURS);
            if (taskStart == null) {
                taskStart = currentTime;
            }

            // 计算当前工作块的结束时间
            taskEnd = currentTime.plusSeconds((long) (toSchedule * 3600));
            remainingHours -= toSchedule;
            currentTime = taskEnd;
            this.accumulatedWorkHours += toSchedule;

            // 如果还有剩余工作，跳到下一个工作日
            if (remainingHours > 0) {
                currentTime = jumpToNextWorkingDay(currentTime);
            }
        }

        // 设置新任务的开始和结束时间
        newTask.setStartTime(taskStart);
        newTask.setEndTime(taskEnd);
    }
}
